﻿using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Sample.Core;
using UnityEngine;
using UnityEngine.UI;

abstract public class OptionUI : MonoBehaviour
{
    abstract public void UpdateFromConfigVar();
    abstract public void UpdateToConfigVar();

    [System.NonSerialized]
    public ConfigVar configVar;

    [System.NonSerialized]
    public bool changed;
    public void OnChanged()
    {
        changed = true;
    }
}

public class OptionsMenu : MonoBehaviour
{
    public OptionToggle toggleTemplate;
    public OptionDropdown dropdownTemplate;
    public OptionInput inputTemplate;
    public OptionHeading headingTemplate;
    public OptionSlider sliderTemplate;

    public ScrollRect scrollRect;
    public GameObject content;

    List<OptionUI> options = new List<OptionUI>();

    float height = 0.0f;

    void AddOption(OptionUI o)
    {
        options.Add(o);
        o.gameObject.SetActive(true);
        var rt = ((RectTransform)o.transform);
        rt.anchoredPosition = new Vector2(rt.anchoredPosition.x, -height);
        height += rt.rect.height;

        // Resize scroll area
        var panelRect = ((RectTransform)transform).rect;
        var contentRect = ((RectTransform)content.transform);
        var cr = contentRect.sizeDelta;
        cr.y = height;
        contentRect.sizeDelta = cr;
    }

    void AddToggle(ConfigVar configVar, string description)
    {
        var input = Instantiate(toggleTemplate, content.transform);
        input.title.text = description;
        input.configVar = configVar;
        AddOption(input);
    }

    void AddInput(ConfigVar configVar, string description)
    {
        var input = Instantiate(inputTemplate, content.transform);
        input.title.text = description;
        input.configVar = configVar;
        AddOption(input);
    }

    void AddDropdown(ConfigVar configVar, string description, List<string> options, List<string> values, string custom = "")
    {
        var drop = Instantiate(dropdownTemplate, content.transform);
        drop.dropdown.ClearOptions();
        drop.dropdown.AddOptions(options);
        if (custom != "")
            drop.dropdown.AddOptions(new List<string> { custom });
        drop.title.text = description;
        drop.values = values;
        drop.configVar = configVar;
        AddOption(drop);
    }

    void AddSpace(float space)
    {
        height += space;
    }

    void AddHeading(string text)
    {
        var heading = Instantiate(headingTemplate, content.transform);
        heading.title.text = text;
        heading.configVar = null;
        AddOption(heading);
    }

    void AddSlider(ConfigVar configVar, string description)
    {
        var slider = Instantiate(sliderTemplate, content.transform);
        slider.title.text = description;
        slider.configVar = configVar;
        slider.slider.minValue = 0;
        slider.slider.maxValue = 1;
        slider.slider.wholeNumbers = false;
        AddOption(slider);
    }

    void Start()
    {
        var res = new List<string>();
        foreach (var r in Screen.resolutions)
            res.Add(r.width + "x" + r.height + "@" + r.refreshRate);

        AddHeading("Graphics settings");
        AddDropdown(RenderSettings.rQuality, "Overall quality", new List<string>(QualitySettings.names), new List<string>(QualitySettings.names));
        AddDropdown(RenderSettings.rResolution, "Screen resolution", res, res, "Custom");
        AddDropdown(RenderSettings.rFullscreen, "Full screen mode", new List<string>() { "Windowed", "Full screen", "Exclusive" }, new List<string>() { "3", "1", "0" });
        AddToggle(RenderSettings.rVSync, "Enable v-sync");
        AddToggle(RenderSettings.rBloom, "Bloom effect");
        AddToggle(RenderSettings.rMotionBlur, "Motion blur effect");
        AddToggle(RenderSettings.rSSAO, "Screen space ambient occlusion");
        AddToggle(RenderSettings.rGrain, "Grain effect");
        AddToggle(RenderSettings.rSSR, "Screen space reflection");
        AddToggle(RenderSettings.rSSS, "Subsurface scattering");
        AddDropdown(RenderSettings.rAAMode, "Anti alias mode", new List<string>() { "Off", "FXAA", "TAA" }, new List<string>() { "off", "fxaa", "taa" });

        AddSpace(100.0f);
        AddHeading("Audio settings");
        AddDropdown(SoundSystem.soundMute, "Audio enabled", new List<string>() { "When focus", "Always", "Never" }, new List<string>() { "-1", "1", "0" });
        AddDropdown(SoundSystem.soundSpatialize, "Output type", new List<string>() { "Speakers", "Headphones" }, new List<string>() { "0", "1" });
        AddSlider(SoundSystem.soundMusicVol, "Music volume");
        AddSlider(SoundSystem.soundSFXVol, "SFX volume");

        Canvas.ForceUpdateCanvases(); // TODO (petera) why is this needed?

        scrollRect.verticalNormalizedPosition = 1f;
    }

    public void UpdateMenu()
    {
        foreach (var o in options)
        {
            if (o.changed)
            {
                o.changed = false;
                o.UpdateToConfigVar();
                Console.EnqueueCommandNoHistory("saveconfig");
            }
            else
                o.UpdateFromConfigVar();
        }
    }

    public void OnGDRP()
    {
#if ENABLE_CLOUD_SERVICES_ANALYTICS
        UnityEngine.Analytics.DataPrivacy.FetchPrivacyUrl(OnUrlReceived, OnFailure);
#endif
    }

#if ENABLE_CLOUD_SERVICES_ANALYTICS
    private void OnFailure(string err)
    {
        GameDebug.LogWarning("Failed to get Data Privacy URL: " + err);
    }

    private void OnUrlReceived(string url)
    {
        Application.OpenURL(url);
    }

#endif
}
